package com.lifang.framework.beans.factory.support;

import cn.hutool.core.util.StrUtil;
import com.lifang.framework.beans.BeansException;
import com.lifang.framework.beans.factory.DisposableBean;
import com.lifang.framework.beans.factory.ObjectFactory;
import com.lifang.framework.beans.factory.config.SingletonBeanRegistry;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 默认 单例bean 注册实现类
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    protected final Object NULL_OBJECT = new Object();

    private final Map<String, DisposableBean> disposableBeans = new HashMap<>();

    /**
     * 一级缓存，普通对象
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(32);

    /**
     * 二级级缓存，提前暴漏对象，没有完全实例化的对象
     */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(32);

    /**
     * 三级缓存，存放代理对象
     */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(32);

    /**
     * 当前正在创建的单例Bean的名称
     */
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    protected void beforeSingletonCreation(String beanName) {
        if (!this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }

    protected boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }

    protected void afterSingletonCreation(String beanName) {
        if (!this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }

    @Override
    public Object getSingleton(String beanName) {
        Object singletonObject = singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = earlySingletonObjects.get(beanName);
            if (singletonObject == null) {
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    @Override
    public void destroySingletons() {
        for (Map.Entry<String, DisposableBean> entry : disposableBeans.entrySet()) {
            try {
                entry.getValue().destroy();
            } catch (Exception e) {
                throw new BeansException("Destroy method on bean with name '" + entry.getKey() + "' threw an exception", e);
            }
        }
        disposableBeans.clear();
    }

    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }

    @Override
    public boolean containsSingleton(String beanName) {
        return singletonObjects.get(beanName) != null || earlySingletonObjects.get(beanName) != null || singletonFactories.get(beanName) != null;
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        if (!this.singletonObjects.containsKey(beanName)) {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
        }
    }

    /**
     * 注册容器销毁时应该需要销毁处理的Bean
     */
    public void registerDisposableBean(String beanName, DisposableBean disposableBean) {
        if (StrUtil.isNotEmpty(beanName) && disposableBean != null) {
            disposableBeans.put(beanName, disposableBean);
        }
    }
}
